﻿using Function = MicroCloud.Authorization.Function;
using Module = MicroCloud.Authorization.Entities.Module;
using ModuleFunction = MicroCloud.Authorization.Entities.ModuleFunction;

namespace MicroCloud.Api.Authorization.Areas.Admin.Controllers.Auth
{
    /// <summary>
    /// 模块信息
    /// </summary>
    [Description("模块信息")]
    [ModuleInfo(Code = "Module", Name = "模块信息", OrderNo = 3, Position = "Auth", PositionName = "授权模块")]
    public class ModuleController : AdminControllerBase
    {
        #region "属性"
        #region "获取 功能权限管理器"
        /// <summary>
        /// 获取 功能权限管理器
        /// </summary>
        protected FunctionAuthManager FunctionAuthManager => ServiceProvider.GetService<FunctionAuthManager>();
        #endregion

        #region "获取 模块仓储"
        /// <summary>
        /// 获取 模块仓储
        /// </summary>
        protected IRepository<Module, long> ModuleRepository => ServiceProvider.GetService<IRepository<Module, long>>();
        #endregion
        #region "获取 模块信息查询数据集"
        /// <summary>
        /// 获取 模块信息查询数据集
        /// </summary>
        public IQueryable<Module> Modules => ModuleRepository.QueryAsNoTracking();
        #endregion

        #region "获取 权限服务"
        /// <summary>
        /// 获取 权限服务
        /// </summary>
        protected IAuthorityService AuthorityService => ServiceProvider.GetService<IAuthorityService>();
        #endregion

        #endregion

        #region "Action方法"
        #region "读取模块"
        /// <summary>
        /// 读取模块
        /// </summary>
        /// <returns>模块信息集合</returns>
        [HttpPost]
        [ModuleInfo]
        [Description("读取")]
        public virtual List<ModuleOutputDto> Read()
        {
            IFunction function = this.GetExecuteFunction();
            Expression<Func<Module, bool>> predicate = m => true;

            List<ModuleOutputDto> modules = CacheService.ToCacheList<Module, ModuleOutputDto>(FunctionAuthManager.Modules, predicate, function);
            return modules;
        }
        #endregion

        #region "读取模块[用户]树"
        /// <summary>
        /// 读取模块[用户]树
        /// </summary>
        /// <param name="userId">用户编号</param>
        /// <returns>模块[用户]树数据</returns>
        [HttpGet]
        [ModuleInfo]
        [Description("读取[用户]树")]
        public virtual List<object> ReadUserModules(long userId)
        {
            Check.GreaterThan(userId, nameof(userId), 0);

            IFunction function = this.GetExecuteFunction();
            Expression<Func<ModuleUser, bool>> predicate = m => m.UserId == userId;

            long[] checkedModuleIds = CacheService.ToCacheArray(FunctionAuthManager.ModuleUsers, predicate, m => m.ModuleId, function);
            long[] rootIds = CacheService.ToCacheList(FunctionAuthManager.Modules, m => m.ParentId == null, ul => new { ul.Id, ul.OrderNo }, function).OrderBy(m => m.OrderNo).Select(m => m.Id).ToArray();

            var authorizedCodes = AuthorityService.GetAuthorizedInfosByUser(userId.ToString()).Select(x => x.FullCode).ToArray();
            var moduleEntities = FunctionAuthManager.Modules.ToArray();
            var functions = FunctionAuthManager.Functions.ToArray();
            var moduleFunctions = FunctionAuthManager.ModuleFunctions.ToArray();

            var result = GetModulesWithChecked(rootIds, checkedModuleIds, authorizedCodes, moduleEntities, functions, moduleFunctions);
            return result;
        }
        #endregion
        #region "读取模块[角色]树"
        /// <summary>
        /// 读取模块[角色]树
        /// </summary>
        /// <param name="roleId">角色编号</param>
        /// <returns>模块[角色]树数据</returns>
        [HttpGet]
        [ModuleInfo]
        [Description("读取[角色]树")]
        public virtual List<object> ReadRoleModules(long roleId)
        {
            Check.GreaterThan(roleId, nameof(roleId), 0);

            IFunction function = this.GetExecuteFunction();
            Expression<Func<ModuleRole, bool>> predicate = m => m.RoleId == roleId;

            long[] checkedModuleIds = CacheService.ToCacheArray(FunctionAuthManager.ModuleRoles, predicate, m => m.ModuleId, function);
            long[] rootIds = CacheService.ToCacheList(FunctionAuthManager.Modules, m => m.ParentId == null, ul => new { ul.Id, ul.OrderNo }, function).OrderBy(m => m.OrderNo).Select(m => m.Id).ToArray();

            var authorizedCodes = AuthorityService.GetAuthorizedInfosByRole(roleId.ToString()).Select(x => x.FullCode).ToArray();
            var moduleEntities = FunctionAuthManager.Modules.ToArray();
            var functions = FunctionAuthManager.Functions.ToArray();
            var moduleFunctions = FunctionAuthManager.ModuleFunctions.ToArray();

            var result = GetModulesWithChecked(rootIds, checkedModuleIds, authorizedCodes, moduleEntities, functions, moduleFunctions);
            return result;
        }
        #endregion

        #region "读取模块功能"
        /// <summary>
        /// 读取模块功能
        /// </summary>
        /// <returns>模块功能信息</returns>
        [HttpPost]
        [ModuleInfo]
        [DependOnFunction(nameof(Read))]
        [Description("读取功能")]
        public virtual PageData<FunctionOutputDtoSimple> ReadFunctions(PageRequest request)
        {
            Check.NotNull(request, nameof(request));
            Check.NotNull(request.FilterGroup, nameof(request.FilterGroup));

            var rulesCount = request.FilterGroup.Rules?.Count == null ? 0 : request.FilterGroup.Rules.Count;
            var groupsCount = request.FilterGroup.Groups?.Count == null ? 0 : request.FilterGroup.Groups.Count;
            if (rulesCount == 0 && groupsCount == 0)
            {
                return new PageData<FunctionOutputDtoSimple>();
            }

            IFunction function = this.GetExecuteFunction();
            Expression<Func<Module, bool>> moduleExp = FilterService.GetExpression<Module>(request.FilterGroup);

            long[] moduleIds = CacheService.ToCacheArray(FunctionAuthManager.Modules, moduleExp, m => m.Id, function);
            var functionIds = FunctionAuthManager.ModuleFunctions.Where(m => moduleIds.Contains(m.ModuleId)).Select(m => m.FunctionId).Distinct().ToArray();
            if (functionIds.Length == 0)
            {
                return new PageData<FunctionOutputDtoSimple>();
            }
            if (request.PageCondition.SortConditions.Length == 0)
            {
                request.PageCondition.SortConditions = new[] { new SortCondition("Area"), new SortCondition("Controller") };
            }
            var page = FunctionAuthManager.Functions.ToPage(m => functionIds.Contains(m.Id),
                request.PageCondition,
                m => new FunctionOutputDtoSimple() { Id = m.Id, Name = m.Name, AccessType = m.AccessType, Area = m.Area, Controller = m.Controller });
            return page.ToPageData();
        }
        #endregion

        #endregion

        #region "受保护方法"
        #region "获取已检查的模块"
        /// <summary>
        /// 获取已检查的模块
        /// </summary>
        /// <param name="rootIds"></param>
        /// <param name="checkedModuleIds"></param>
        /// <param name="authorizedCodes"></param>
        /// <param name="moduleEntities"></param>
        /// <param name="functions"></param>
        /// <param name="moduleFunctions"></param>
        /// <returns></returns>
        [NonAction]
        [NonFunction]
        protected virtual List<object> GetModulesWithChecked(long[] rootIds, long[] checkedModuleIds, string[] authorizedCodes
            , Module[] moduleEntities, Function[] functions, ModuleFunction[] moduleFunctions)
        {
            #region "效率问题，注释备查"
            //var modules = FunctionAuthManager.Modules.Where(m => rootIds.Contains(m.Id)).OrderBy(m => m.OrderNo).Select(m => new
            //{
            //    m.Id,
            //    m.Name,
            //    m.FullName,
            //    m.Remark,
            //    m.Code,
            //    m.FullCode,
            //    m.OrderNo,
            //    m.ParentId,
            //    ChildIds = FunctionAuthManager.Modules.Where(n => n.ParentId == m.Id).OrderBy(n => n.OrderNo).Select(n => n.Id).ToList()
            //}).ToList();
            #endregion
            var modules = moduleEntities.Where(m => rootIds.Contains(m.Id)).OrderBy(m => m.OrderNo).Select(m => new
            {
                m.Id,
                m.Name,
                m.FullName,
                m.Remark,
                m.Code,
                m.FullCode,
                m.OrderNo,
                m.ParentId,
                ChildIds = moduleEntities.Where(n => n.ParentId == m.Id).OrderBy(n => n.OrderNo).Select(n => n.Id).ToList()
            }).ToList();
            List<object> nodes = new();
            foreach (var item in modules)
            {
                if (item.ChildIds.Count == 0 && !IsRoleLimit(item.Id, functions, moduleFunctions))
                {
                    continue;
                }
                var node = new
                {
                    item.Id,
                    item.Name,
                    FullName = I18N.T(item.FullName),
                    item.Remark,
                    item.Code,
                    item.FullCode,
                    item.OrderNo,
                    item.ParentId,
                    IsChecked = checkedModuleIds.Contains(item.Id),
                    HasAuth = checkedModuleIds.Contains(item.Id) || authorizedCodes.Contains(item.FullCode),
                    HasChildren = item.ChildIds.Count > 0,
                    Children = item.ChildIds.Count > 0 ? GetModulesWithChecked(item.ChildIds.ToArray(), checkedModuleIds, authorizedCodes, moduleEntities, functions, moduleFunctions) : new List<object>()
                };
                if (node.Children.Count == 0 && !IsRoleLimit(node.Id, functions, moduleFunctions))
                {
                    continue;
                }

                nodes.Add(node);
            }
            return nodes;
        }
        #endregion
        #region "是否角色限制"
        /// <summary>
        /// 是否角色限制
        /// </summary>
        /// <param name="moduleId"></param>
        /// <param name="functions"></param>
        /// <param name="moduleFunctions"></param>
        /// <returns></returns>
        [NonAction]
        [NonFunction]
        protected virtual bool IsRoleLimit(long moduleId, Function[] functions, ModuleFunction[] moduleFunctions)
        {
            #region "效率问题，注释备查"
            //return FunctionAuthManager.Functions
            //    .Where(m => FunctionAuthManager.ModuleFunctions.Where(n => n.ModuleId == moduleId).Select(n => n.FunctionId).Contains(m.Id))
            //    .Any(m => m.AccessType == FunctionAccessType.RoleLimit);
            #endregion
            return functions.Where(m => moduleFunctions.Where(n => n.ModuleId == moduleId).Select(n => n.FunctionId).Contains(m.Id)).Any(m => m.AccessType == FunctionAccessType.RoleLimit);
        }
        #endregion

        #endregion

    }

}
